#ifndef CDNA_PROT_H
#define CDNA_PROT_H


#include <string>
#include <iterator>


namespace cdna_prot
{
	inline unsigned to_uint(char c){return static_cast<unsigned>(c);}
	struct t_validate_prot
	{
		char table [256];
		// default to allowing 'X' but not "BJOUZ"
		// empty string = A to Z, a-z and -*_~^.

		// if stop_is_X, stop asterisks are replaced by X
		t_validate_prot(std::string letters = "ACDEFGHIKLMNPQRSTVWXYacdefghiklmnpqrstvwxy",
						bool to_upper_case = true, 
						bool asterisk_is_X = true, 
						bool letters_are_valid = true);
		void validate(std::string& sequence)
		{
			std::string::iterator first	=  sequence.begin();
			std::string::iterator last	=  sequence.end();
			std::string::iterator dest	=  first;
		
			for (; first != last; ++first)
				if ((*dest = table[to_uint(*first)]) != 0)
					++dest;
			sequence.erase(dest, last);
		}
	};
	
	
	void complement_cdna_index(std::string& cdna);
	void validate_cdna_to_index(std::string& sequence);
	std::string cdna_index_to_text(std::string sequence);
	std::string cdna_index_to_prot(const std::string& cdna);
	
	struct t_cdna_index_to_prot
	{
		//static char table [16][16][16];
		static char table [6][6][6];
		static bool initialized;
		char operator ()(const char * cdna) const
		{
			return table[static_cast<unsigned>(* cdna   )]
						[static_cast<unsigned>(*(cdna+1))]
						[static_cast<unsigned>(*(cdna+2))];
		}
	};
	const char DNA_A = 1;
	const char DNA_C = 2;
	const char DNA_G = 3;
	const char DNA_T = 4;
	const char DNA_N = 5;

//	const char DNA_Y = 6;
//	const char DNA_R = 7;
//	const char DNA_M = 8;
//	const char DNA_K = 9;
//	const char DNA_W = 10;
//	const char DNA_S = 11;
//	const char DNA_V = 12;
//	const char DNA_B = 13;
//	const char DNA_H = 14;
//	const char DNA_D = 15;


	void initialize_conversion_buffers();
	
template <class ITER>
std::string cdna_index_to_prot(ITER beg, ITER end)
{
	std::string ret;
	unsigned prot_len  = std::distance(beg, end) / 3;
	ret.reserve(prot_len);
	// make sure whole number of codons
	end = beg + prot_len * 3;
	for (;beg < end; beg += 3)
	{
		ret += t_cdna_index_to_prot()(&*beg);
	}
	return ret;
}

	
}
	


namespace{
	struct initialize_buffers
	{initialize_buffers(){	cdna_prot::initialize_conversion_buffers();}};
	initialize_buffers init_buffers;
}

#endif
